Hints for 4k Intro Coders

Franky / Smash Designs

Due to incorrect information in various diskmags and other electronic publications I unfortunately have to state that there is a lack of knowledge regarding 4k intros. For this reason I want to clarify some important points.

I'm simply fed up of people who know nothing about 32-bit PM coding claiming that 32-bit code were bigger or that Windows files have to be at least 8k. This is not going to be a full-fledged How-to-Do-it-even-being-a-lamer article but definitely a very good help-doc for people who have already tried a couple of things in the 4k area.

32-bit code.

32-bit code is not bigger than 16-bit code. On the contrary, it is smaller, for this reason:

16-bit RM: mov ax, [ address ] -> 1 byte opcode, 2 bytes addressing
32-bit PM: mov eax, [ ebx + relative_address ] -> 1 byte opcode, 1 byte relative addressing

This means, you have smaller opcodes, but you can operate with 32-bit values. These are two advantages in one.

The trick is: put everything into one structure, then use

mov ebx, address

only once, and now you can use relative addressing for the rest of the program. Apart from that, you need not use 4 bytes for the address. Define your data segment as USE16, and the Assembler will use the 67h address-size prefix, followed by an address index sized just 2 bytes.

Win2k exes can be smaller than 8k.

After assembling, the files become at least 8k in size because Windows 2000 demands the .rdata segment in addition to the code segment. Since each segment (also called section in PE jargon) has a minimal alignment of 4 kbytes (due to a memory page with a size of exact 4k), the result is a file of 8k.

But it is wrong that it has to stay 8k because 80% of its contents are zero-bytes. Even programs created with Visual C++ can be reduced to 350 kbytes, as Entropy of Teklords has proven.

About the Win9x/Win2k conflict.

PE files use file alignment. That means that the header is usually aligned to 512 bytes (if Win9x is used). In WinNT and Win2k the minimal alignment is 16 bytes.

The alignment may be a bit disturbing, but it effectively hardly increases the size of the programs as you can fill this space with data.

Exe stub.

Usually every Windows program is preceded by a 512-byte 16-bit DOS stub. The common DOS MZ header has a size of at least 28 bytes (unaligned) or 32 bytes (16-byte aligned). Windows requires the MZ string, but not the whole exe header.

In order to get rid of the stub, create a file like:

db "MZ"
push dx
ret

Under DOS this will be run as a COM file. Windows, however, checks for the MZ and tests what's included in the file at position 3ch. Here you have to enter the offset of the PE header, which usually is 40h.

In order to get the files as small as possible, use the above pseudo-exe header, enter the length of the complete file (PE + MZ) as the EXE file size, fill the exe-header with 10 bytes and start the PE header at byte 10. The dword at position 3ch now is partly located in the PE header. Here you enter the beginning of the PE header as a WORD (!), which should have the value 10 (decimal).

This will result in the smallest MZ stub possible.

Packing Win32 intros.

UPX won't help much to get the intros small. The trick is to make the file appear to be a standard DOS file and pack it with a DOS packer. The benefit is a smaller overhead for the packer. Moreover, the Windows exe header is packed as well.

I released a tool for this purpose, requests go to franky@scene.at.

Franky / Smash Designs